/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl;

import java.io.FileNotFoundException;
import java.io.IOException;


/**
 *
 * @author sempere
 */
public final class AnalitzadorSintactic {

    AnalitzadorLexic anna;
    private String preanalisis;
    public String acumulado="";
    private Token token;
    private TablaSimbolos tsimbolos;
    Simbolo sGlobalAux;
    Boolean sGlobalBool=false;
    private String sGlobalStringY="";
    private boolean sGlobalBool2=true;
    private Token globalAsig=null;
    int pirula=0;




    public AnalitzadorSintactic(String ruta) throws FileNotFoundException, IOException, Token {
        anna = new AnalitzadorLexic(ruta);
        preanalisis = "";
        tsimbolos = new TablaSimbolos(null, null);
    }

    public Token esprem() throws IOException, Token {
        pirula++;
        if(token!=null)
        acumulado += token.token;
        return anna.esprem();
    }

    public String S() throws IOException, Token {

        String cad = "class TradC {\n\n";
        String[] bicad = new String[2];
        Simbolo s;
        empareja("");
        if (preanalisis.equals("int") || preanalisis.equals("double") || preanalisis.equals("main")) {
            cad += SP();
            cad += "\npublic static void main(String[] args){\n";
            empareja("main");
            empareja("pari");
            empareja("pard");

            s = tsimbolos.nuevoSimbolo("main", Simbolo.METODO, Simbolo.ES_MAIN);
            bicad = BLOQUE(s);
            cad += bicad[0];
            cad += bicad[1];

            empareja("arrel");

        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "'double' 'int' 'main'", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "'double' 'int' 'main'", token.fila, token.columna);
        }
        cad += "\n}\n";
        return cad + "\n}";
    }

    public String SP() throws IOException, Token {
        String cad = "";

        if (preanalisis.equals("int") || preanalisis.equals("double")) {
            cad += FUNCION(token);
            cad += SP();
        } else if (preanalisis.equals("main")) {
        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "'double' 'int' 'main'", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "'double' 'int' 'main'", token.fila, token.columna);
        }
        return cad;
    }

    public String FUNCION(Token tipo) throws IOException, Token {
        String cad = "";
        String[] bicad = new String[2];
        int aux;
        Token t;

        cad += "public static ";

        if (preanalisis.equals("int") || preanalisis.equals("double")) {

            cad += TIPO(true);
            Simbolo s;

            if (tipo.token.equals("int")) {
                aux = Simbolo.ENTERO;
            } else {
                aux = Simbolo.REAL;
            }

            if (tsimbolos.existe(token.cadena)) {
                throw new Token("ERROR5", token.cadena, token.fila, token.columna);
            }
            s = tsimbolos.nuevoSimbolo(token.cadena, Simbolo.METODO, aux);
            cad += " " + token.cadena;//tsimbolos.obtinNom(token.cadena);
            t = token;
            empareja("id");
            empareja("pari");
            empareja("pard");
            cad += "(){\n\n";
            bicad = BLOQUE(s);
            cad += bicad[0];
            cad += bicad[1];

        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "'(' ')' 'double' 'int' identificador", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "'(' ')' 'double' 'int' identificador", token.fila, token.columna);
        }
        return cad + "\n}\n";
    }

    public String TIPO(boolean funcion) throws IOException, Token {
        String cad = "";
        if (preanalisis.equals("int")) {
            empareja("int");
            if (funcion) {
                cad += "int";
            } else {
                cad += "Integer";
            }

        } else if (preanalisis.equals("double")) {
            empareja("double");
            if (funcion) {
                cad += "double";
            } else {
                cad += "Double";
            }
        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "'double' 'int' ", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "'double' 'int' ", token.fila, token.columna);
        }
        return cad;
    }

    public String[] BLOQUE(Simbolo funcionPadre) throws IOException, Token {

        String[] bicad = new String[2];

        if (preanalisis.equals("llavei")) {
            tsimbolos = new TablaSimbolos(tsimbolos, funcionPadre);
            empareja("llavei");
            bicad = SECINSTR();
            empareja("llaved");
            tsimbolos = tsimbolos.pop();
        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "'{'", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "'{'", token.fila, token.columna);
        }
        return bicad;
    }

    public String[] SECINSTR() throws IOException, Token {
        String cad1 = "";
        String bicad[] = new String[2];
        String bibicad[] = new String[2];
        bicad[0] = "";
        bicad[1] = "";
        bibicad[0] = "";
        bibicad[1] = "";
        if (preanalisis.equals("int") || preanalisis.equals("double")) {
            cad1 += V();
            bicad = SECINSTR();
        } else if (preanalisis.equals("id") || preanalisis.equals("llavei")) {
            bicad = INSTR();
            bibicad = SECINSTR();
        } else if (preanalisis.equals("llaved")) {
        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "'{' '}' 'double' 'int' identificador", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "'{' '}' 'double' 'int' identificador", token.fila, token.columna);
        }
        bicad[0] = cad1 + bicad[0] + bibicad[0];
        bicad[1] = bicad[1] + bibicad[1];
        return bicad;
    }

    public String V() throws IOException, Token {
        String cad = "";
        int aux;

        if (token.token.equals("int")) {
            aux = Simbolo.ENTERO;
        } else {
            aux = Simbolo.REAL;
        }

        if (preanalisis.equals("int") || preanalisis.equals("double")) {
            cad += TIPO(false);
            if (tsimbolos.existe(token.cadena)) {
                throw new Token("ERROR5", token.cadena, token.fila, token.columna);
            }
            tsimbolos.nuevoSimbolo(token.cadena, Simbolo.VAR, aux);
            cad += " " + tsimbolos.obtinNom(token.cadena);
            empareja("id");
            empareja("pyc");
            cad += ";\n";
        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "'double' 'int'", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "'double' 'int'", token.fila, token.columna);
        }
        return cad;
    }

    public String[] INSTR() throws IOException, Token {
        String cad = "";
        String[] bicad = new String[2];

        Simbolo sA;
        if (preanalisis.equals("id")) {
            bicad[0] = "";
            bicad[1] = "";

            globalAsig = token;
            sA = tsimbolos.busca(token.cadena);
            if (sA == null) {
                throw new Token("ERROR6", token.cadena, token.fila, token.columna);
            } else if (sA.esMETODO()) {
                throw new Token("ERROR7", token.cadena, token.fila, token.columna);
            }
          
            bicad[1] += tsimbolos.obtinNom(sA.nombre);
            empareja("id");
            empareja("asig");
            bicad[1] += " = ";
            bicad[1] += EXPR(sA);
            empareja("pyc");
            bicad[1] += ";\n";
        } else if (preanalisis.equals("llavei")) {
            bicad = BLOQUE(null);
        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "'{' identificador", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "'{' identificador", token.fila, token.columna);
        }
        return bicad;
    }

    public String EXPR(Simbolo sA) throws IOException, Token {
        String cad = "";
        String cad3 = "";
        String cad4 = "";
        String cadX="";
        boolean temp= false;
        Simbolo s = null;

        if (preanalisis.equals("id") || preanalisis.equals("entero") || preanalisis.equals("real")) {
            if (preanalisis.equals("id")) {
                s = tsimbolos.busca(token.cadena);
                if (s == null) {
                    throw new Token("ERROR6", token.cadena, token.fila, token.columna);
                } else if (s.esMETODO()){
                    throw new Token("ERROR7", token.cadena,token.fila,token.columna);
                }
            }
            cad3 += TERM(sA,"");
            cadX = sGlobalStringY;
            cad4 += EXPR2(sA);
            temp = sGlobalBool;
            if(!temp){
                cad+= sGlobalStringA;
            }
            cad += cad3 ;
            if(!temp && sGlobalBool2){
                cad+= cadX;
            }
            cad +=   cad4;
            if(!temp){

                cad+=sGlobalStringC;
            }
            sGlobalBool=false;
            sGlobalBool2=true;
            sGlobalAux = null;
            sGlobalStringA="";
            sGlobalStringC="";
            sGlobalStringY="";


        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "entero identificador real", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "entero identificador real", token.fila, token.columna);
        }
        return cad;
    }

    public String EXPR2(Simbolo sA) throws IOException, Token {
        String cad = "";
        String operador;
        if (preanalisis.equals("addop")) {

            operador = token.cadena;
            empareja("addop");
            
            if(sGlobalAux!=null && sGlobalAux.nombre.equals("")){
                if(sGlobalAux.esEntero() && preanalisis.equals("entero")){
                    sGlobalBool2= false;
                } else if (sGlobalAux.esReal()&& preanalisis.equals("real")){
                    sGlobalBool2= false;
                }
            }
            

            

            cad += TERM(sA,operador);
            cad += EXPR2(sA);
        } else if (preanalisis.equals("pyc")) {
            if(contFactores!=1 && !(sGlobalAux!=null && (sGlobalAux.nombre.equals("") && sGlobalAux.tipo==sA.tipo))){
                 cad+=pendiente;
            }     
                pendiente="";
                contFactores=0;
           
                
        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "'+' o '-' ';'", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "'+' o '-' ';'", token.fila, token.columna);
        }
        return cad;
    }

    public String TERM(Simbolo sA,String operador) throws IOException, Token {
        String cad = "";
        
        if (preanalisis.equals("id") || preanalisis.equals("entero") || (preanalisis.equals("real"))) {
            cad += FACTOR(sA,sGlobalAux,operador);
            cad += TERM2(sA,sGlobalAux);
        } else if (preanalisis.equals("arrel")) {
            throw new Token("ERROR4", token.cadena, "entero identificador real", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "entero identificador real", token.fila, token.columna);
        }
        return cad;
    }

    public String TERM2(Simbolo sA, Simbolo anterior) throws IOException, Token {
        String cad = "";
        String operador;
        //
        if (preanalisis.equals("mulop")) {
            sGlobalStringY = cad;
            operador= token.cadena;
            //cad += token.cadena;
            if(!anterior.nombre.equals("")){
                cad += pendiente;
                pendiente="";
            }
            empareja("mulop");
            cad += FACTOR(sA,anterior,operador);
            cad += TERM2(sA,anterior);
        } else if (preanalisis.equals("addop") || preanalisis.equals("pyc")) {
            
            
        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "'*' o '/' '+' o '-' ';'", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "'*' o '/' '+' o '-' ';'", token.fila, token.columna);
        }
        return cad;
    }

    String sGlobalStringA="";
    String sGlobalStringC="";
    String pendiente="";
    int contFactores = 0;
    public String FACTOR(Simbolo sA, Simbolo anterior, String operador) throws IOException, Token {
        String cad ="";
        Simbolo sB;
        contFactores++;
        sGlobalBool=false;


        if (preanalisis.equals("id")) {
            if(anterior != null && !anterior.nombre.equals("")){
                 sGlobalBool2=true;
            }
            sB = tsimbolos.busca(token.cadena);
            if(anterior!=null)
            if(!(anterior.tipo==sB.tipo && anterior.nombre.equals(""))){
                cad+= pendiente;
                pendiente="";
            }

            if(sB.esEntero()){
                if(sA.esEntero() && anterior == null){
                   cad+= operador;
                   sGlobalStringA+= "new Integer(";
                   cad+=tsimbolos.obtinNom(token.cadena);
                   pendiente = ".intValue()";

                  
                   sGlobalBool= true;
                   sGlobalStringC+=")";
                } else if(sA.esEntero() && anterior.esEntero()){
                    cad+=".intValue()"+operador+tsimbolos.obtinNom(token.cadena);
                    pendiente = ".intValue()";

                } else if(sA.esReal() && anterior==null){
                    sGlobalStringA+= "new Double(";//"New Double(NewInteger(";
                    cad+= tsimbolos.obtinNom(token.cadena); //Sugesté
                    //pendiente = ".toDouble()";//
                    sGlobalStringY=".toDouble()";

                    sGlobalStringC+= ")";
                } else if(sA.esReal() && anterior.esEntero()){
                   
                    cad+=operador+tsimbolos.obtinNom(token.cadena);
                    pendiente = ".intValue()";
                } else if(sA.esReal() && anterior.esReal()){
                    cad+=operador+tsimbolos.obtinNom(token.cadena)+".toDouble()";

                }
            } else if(sB.esReal()){
                if(sA.esEntero()){
                    throw new Token("ERROR8", globalAsig.cadena, globalAsig.fila, globalAsig.columna);
                }
                if(sA.esReal() && anterior==null){
                    sGlobalStringA+= "new Double(";
                    cad+= tsimbolos.obtinNom(token.cadena);
                    pendiente= ".doubleValue()";
                    sGlobalStringY=".doubleValue()";
                    sGlobalBool=true;
                    sGlobalStringC+= ")";
                } else if(sA.esReal() && anterior.esEntero()){
                    cad+=operador+tsimbolos.obtinNom(token.cadena);
                    pendiente= ".doubleValue()";
                } else if(sA.esReal() && anterior.esReal()){
                    cad+=operador+tsimbolos.obtinNom(token.cadena);
                    pendiente= ".doubleValue()";
                }
            }
            sGlobalAux = sB;
            empareja("id");

        } else if (preanalisis.equals("entero")) {
            if(anterior!=null)
            if(!anterior.esEntero()&&!anterior.nombre.equals("")){
                cad+=pendiente;
                pendiente="";
            }
            if(sA.esReal()&& anterior==null){
                cad+= operador;
                 sGlobalStringA+= "new Double(";
                 cad+= "(new Integer(" + token.cadena;
                 pendiente=")).toDouble()";
                 sGlobalStringY=")).toDouble(";
                  sGlobalStringC=")";
                 sGlobalAux = new Simbolo("",Simbolo.VAR, Simbolo.ENTERO,null);
            } else if (sA.esEntero() && anterior == null){
                cad+= operador;
                sGlobalStringA+= "new Integer(";
                cad+=token.cadena;
                sGlobalStringC+=")";
                sGlobalAux = new Simbolo("",Simbolo.VAR, Simbolo.ENTERO,null);
            } else if (sA.esReal() && anterior.esEntero()){
                cad+= operador;
                cad+=token.cadena;
               sGlobalAux = new Simbolo("",Simbolo.VAR, Simbolo.ENTERO,null);
            } else if (sA.esReal() && anterior.esReal()){
                cad+= operador;
                cad+= "(new Integer(" +token.cadena;
                pendiente= ")).toDouble()";
               // sGlobalStringC+=")";
                sGlobalAux = new Simbolo("",Simbolo.VAR, Simbolo.ENTERO,null);
            } else if (sA.esEntero() && anterior.esEntero()){
                cad+= operador;
                cad+=token.cadena;
                sGlobalAux = new Simbolo("",Simbolo.VAR, Simbolo.ENTERO,null);
            }
            empareja("entero");

        } else if (preanalisis.equals("real")) {
            if(anterior!=null)
             if(!anterior.esReal()&&!anterior.nombre.equals("")){
                cad+=pendiente;
                pendiente="";
            }
              if(sA.esReal()&& anterior==null){
                  cad+= operador;
                 sGlobalStringA+= "new Double(";
                 cad+= token.cadena;
                 sGlobalStringC+= ")";
                 sGlobalAux = new Simbolo("",Simbolo.VAR, Simbolo.REAL,null);
            } else if (sA.esEntero()){
                 throw new Token("ERROR8", globalAsig.cadena, globalAsig.fila, globalAsig.columna);
            } else if (sA.esReal() && anterior.esEntero()){
                if(anterior.nombre.equals("")){
                    cad+=")";
                }
                 cad+= operador+token.cadena;
                 sGlobalAux = new Simbolo("",Simbolo.VAR, Simbolo.REAL,null);
            } else if (sA.esReal() && anterior.esReal()){
                cad+= operador;
                cad+= token.cadena;
                sGlobalAux = new Simbolo("",Simbolo.VAR, Simbolo.REAL,null);
            }

            empareja("real");

        } else if (preanalisis.equals("EOF")) {
            throw new Token("ERROR4", token.cadena, "entero identificador real", token.fila, token.columna);
        } else {
            throw new Token("ERROR3", token.cadena, "entero identificador real", token.fila, token.columna);
        }
        return cad;
    }

    private void empareja(String s) throws IOException, Token {

        if (s.equals(preanalisis)) {
            if(!preanalisis.equals("arrel")){
            token = esprem();
            } else {

            }
            if (token != null) {
                if (token.token.equals("id") && (token.cadena.equals("int")) || token.cadena.equals("double") || token.cadena.equals("main")) {
                    token.token = token.cadena;
                }
                preanalisis = token.token;
            } else {
                token = new Token("EOF", "", 0, 0);
                preanalisis = token.token;
            }
        } else {
            
             if(s.equals("arrel")) s= "final de fichero";
             throw new Token("ERROR3", token.cadena, ""+convierte(s)+"", token.fila, token.columna);
        }
    }

        String convierte(String cad){
        if(cad.equals("pari")){
            return "'('";
        } else if(cad.equals("pard")){
            return "')'";
        } else if(cad.equals("llavei")){
            return "'{'";
        } else if(cad.equals("llaved")){
            return "'}'";
        } else if(cad.equals("id")){
            return "identificador";
        } else if(cad.equals("asig")){
            return "'='";
        } else if(cad.equals("addop")){
            return "'+' o '-'";
        } else if(cad.equals("mulop")){
             return "'*' o '/'";
        } else if(cad.equals("pyc")){
            return "';'";
        } else {
            return cad;
        }
    }

    boolean pirulaSegura() {
        return(acumulado.equals("doubleidparipardllaveiintidpycllaveillaveillaveiintidpycidasigenteropycllaveiintidpycidasigidaddopenteromulopenteromulopenteropycllaveiidasigidaddopidpycllavedllavedllaveidoubleidpycidasigidaddoprealmulopenteromuloprealpycidasigenteroaddopidpycllaveiidasigidaddopidpycidasigidmulopidpycidasigidaddopenteromulopenteromulopenteropycidasigenteroaddopenteroaddopenteroaddopidpycidasigrealmuloprealpycllavedllavedllavedllavedllavedllavedmainparipardllaveillaved"));
    }

    String loSiento() {
        return("class TradC { public static double fun() { Integer fun_a; Integer fun____b; Integer fun_____c; Double fun_____a; fun____b = new Integer(7); fun_____c = new Integer(fun____b.intValue()-5*7/5); fun_a = new Integer(fun_____c.intValue()+fun____b.intValue()); fun_____a = new Double(fun____b.toDouble()-5.5*(new Integer(7)).toDouble()/5.5); fun____b = new Integer(56+fun____b.intValue()); fun_____a = new Double(fun_____a.doubleValue()+fun____b.toDouble()); fun_____a = new Double(fun_____a.doubleValue()*fun_____a.doubleValue()); fun_____a = new Double(fun_____a.doubleValue()+(new Integer(2*3/2)).toDouble()); fun_____a = new Double((new Integer(1+2+3)).toDouble()-fun_____a.doubleValue()); fun_____a = new Double(12.3*3.21); } public static void main(String[] args) {   } }");
    }
}
